package com.gxc.aspect;

import com.alibaba.fastjson.JSONObject;
import com.gxc.utils.LogUtils;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

/**
 * AOP.
 *
 * @author 宫新程
 * @since 2018/12/15 5:29 PM
 */
@Slf4j
@Aspect
@Component
public class MyAspect {

  @Pointcut("execution(* com.gxc.controller.LoginController.*(..))")
  public void loginControllerPointCut() {}

  /** 测试@RestController 注解在class上的类的切面. */
  @Around("@within(org.springframework.web.bind.annotation.RestController)")
  public Object testAnnotationAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
    MethodSignature methodSignature = (MethodSignature) proceedingJoinPoint.getSignature();
    Method method = methodSignature.getMethod();
    // 方法名称
    String methodName = method.getName();
    // 获取参数的key
    String[] parameterNames = methodSignature.getParameterNames();
    // 获取入参
    Object[] args = proceedingJoinPoint.getArgs();
    String className = proceedingJoinPoint.getTarget().getClass().getName();

    /** 将入参放封装到map中. */
    Map<String, Object> paramMap = new HashMap<>();
    if (parameterNames != null && parameterNames.length > 0) {
      for (int i = 0; i < parameterNames.length; i++) {
        if (args[i] instanceof ServletRequest) {
          continue;
        }
        paramMap.put(parameterNames[i], args[i]);
      }
    }
    log.info("methodName：" + methodName);
    log.info("className：" + className);
    log.info("param：" + JSONObject.toJSONString(paramMap));

    /** 需要传递入参？：都行（建议加上）。 */
    Object proceed = proceedingJoinPoint.proceed(args);

    log.info("切面执行结束...");
    return proceed;
  }

  /** LoginController的拦截器. */
  // @Around("loginControllerPointCut()")
  public Object loginControllerAspect(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
    // 获取request
    ServletRequestAttributes servletRequestAttributes =
        (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
    HttpServletRequest request = servletRequestAttributes.getRequest();
    LogUtils.showAspectLog(request);
    // 计算请求耗时
    long start = System.currentTimeMillis();
    Object proceed = proceedingJoinPoint.proceed();
    long end = System.currentTimeMillis();
    log.info("耗时：" + (end - start) + " ms");
    return proceed;
  }
}
